package com.lfz.demo.controller;

import com.lfz.demo.common.enums.LogType;
import com.lfz.demo.common.enums.MenuType;
import com.lfz.demo.common.target.HoneyLogs;
import com.lfz.demo.entity.Notice;
import com.lfz.demo.entity.PopulationNews;
import com.lfz.demo.entity.User;
import com.lfz.demo.service.NoticeService;
import com.lfz.demo.utils.RedisUtil;
import com.lfz.demo.vo.DataView;
import com.lfz.demo.vo.NoticeVo;
import com.lfz.demo.vo.PopulationNewsVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author lfz
 * @date 2025/3/26 16:27
 * 该java文件是一个 Spring Boot 的控制器类 NoticeController，
 * 用于处理与公告（Notice）相关的 HTTP 请求。
 * 它提供了公告的分页查询、删除、新增、修改和批量删除等功能。
 *
 * @RestController：表明这是一个 RESTful 风格的控制器，会自动将方法的返回值转换为 JSON 格式。
 * @RequestMapping("/notice")：为该控制器下的所有请求映射添加 /notice 前缀。
 * @Autowired：自动注入 NoticeService 实例，用于处理公告的业务逻辑。
 */
@RestController
@RequestMapping("/notice")
public class NoticeController {

    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
    // 缓存时间常量（单位：分钟）
    private static final int CACHE_EXPIRE = 60; //缓存过期时间（60分钟）。
    private static final String CACHE_PREFIX = "news:"; //缓存键前缀，避免键冲突。

    @Autowired
    private NoticeService noticeService;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * jpa分页查询所有的公告信息
     */
    @GetMapping("/selectAllNotice")
    public DataView selectAllNotice(NoticeVo noticevo){
        String cacheKey = generateCacheKey(noticevo);   // 设置唯一缓存键

        try {
            // 尝试从缓存中获取
            DataView cachedData = (DataView) redisUtil.get(cacheKey);
            if (cachedData != null){
//                logger.info("命中缓存：{}", cacheKey);
                logger.info( cacheKey);
                return cachedData;
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("Redis访问异常，降级到数据库查询", e);
        }

        try {

            // 创建分页对象
            Pageable pageable = PageRequest.of(noticevo.getPage() - 1, noticevo.getLimit());

            // 创建查询条件
            Specification<Notice> spec = (root, query, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                if (noticevo.getTitle() != null && !noticevo.getTitle().isEmpty()) {
                    predicates.add(criteriaBuilder.like(root.get("title"), "%" + noticevo.getTitle() + "%"));
                }
                if (noticevo.getType() != null && !noticevo.getType().isEmpty()) {
                    predicates.add(criteriaBuilder.like(root.get("type"), "%" + noticevo.getType() + "%"));
                }
                if (noticevo.getStatus() != null && !noticevo.getStatus().isEmpty()) {
                    predicates.add(criteriaBuilder.like(root.get("status"), "%" + noticevo.getStatus() + "%"));
                }

                // 使得创建时间最新的在最前面
                query.orderBy(criteriaBuilder.desc(root.get("createTime")));
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            };

            // 分页查询
            Page<Notice> page = noticeService.findByPage(spec, pageable);

            // 返回数据封装
            DataView dataView = new DataView(page.getTotalElements(), page.getContent());

            // 异步缓存结果
            cacheResultAsync(cacheKey, dataView);
            return dataView;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("公告/通知查询异常", e);
            return new DataView(0L, Collections.emptyList());
        }
    }

    /**
     * 新增公告/通知
     */
    @HoneyLogs(operation = "新增", type = LogType.ADD, menu = MenuType.SYSNOTICE)
    @PostMapping("/addNotice")
    public DataView addNotice(Notice notice) {
        // 确保新增时 id 为 null
        if (notice.getId() != null) {
            notice.setId(null);
        }
        notice.setCreateTime(new Date());
        setOperatorInfo(notice);
        return saveOrUpdateNotice(notice, "新增公告/通知成功！", "发生错误，新增公告/通知失败！请联系管理员进行调试！");
    }

    /**
     * 修改公告/通知
     */
    @HoneyLogs(operation = "修改", type = LogType.UPDATE, menu = MenuType.SYSNOTICE)
    @PostMapping("/updateNotice")
    public DataView updateNotice(Notice notice) {
        notice.setModifiedTime(new Date());
        notice.setStatus("2");
        setOperatorInfo(notice);
        return saveOrUpdateNotice(notice, "编辑公告/通知成功！", "发生错误，编辑公告/通知失败！请联系管理员进行调试！");
    }

    /**
     * 发布公告/通知
     */
    @HoneyLogs(operation = "发布", type = LogType.UPDATE, menu = MenuType.SYSNOTICE)
    @PostMapping("/publishNotice")
    public DataView publishNotice(Notice notice) {
        notice.setModifiedTime(new Date());
        notice.setStatus("0");
        setOperatorInfo(notice);
        return saveOrUpdateNotice(notice, "发布公告/通知成功！", "发生错误，发布公告/通知失败！请联系管理员进行调试！");
    }

    /**
     * 关闭公告/通知
     */
    @HoneyLogs(operation = "关闭", type = LogType.UPDATE, menu = MenuType.SYSNOTICE)
    @PostMapping("/closeNotice")
    public DataView closeNotice(Notice notice) {
        notice.setModifiedTime(new Date());
        notice.setStatus("1");
        setOperatorInfo(notice);
        return saveOrUpdateNotice(notice, "关闭公告/通知成功！", "发生错误，关闭公告/通知失败！请联系管理员进行调试！");
    }

    /**
     * 设置操作人信息
     */
    private void setOperatorInfo(Notice notice) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Object userObj = request.getSession().getAttribute("user");
            if (userObj instanceof User) {
                User user = (User) userObj;
                if (notice.getCreateTime() != null) {
                    notice.setCreatedUser(user.getUsername());
                }
                if (notice.getModifiedTime() != null) {
                    notice.setModifiedUser(user.getUsername());
                }
            } else {
                if (notice.getCreateTime() != null) {
                    notice.setCreatedUser("system");
                }
                if (notice.getModifiedTime() != null) {
                    notice.setModifiedUser("system");
                }
            }
        }
    }

    /**
     * 保存或更新公告并处理结果
     */
    private DataView saveOrUpdateNotice(Notice notice, String successMsg, String errorMsg) {
        DataView dataView = new DataView();
        boolean b;
        if (notice.getId() == null) {
            b = noticeService.save(notice);
        } else {
            b = noticeService.updateById(notice);
        }
        if (b) {
            // 清理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg(successMsg);
        } else {
            dataView.setCode(100);
            dataView.setMsg(errorMsg);
        }
        return dataView;
    }

    /**
     * 删除
     */
    @HoneyLogs(operation = "删除", type = LogType.DELETE, menu = MenuType.SYSNOTICE)
    @PostMapping("/deleteById")
    public DataView deleteById(Integer id){
        DataView dataView = new DataView();

        boolean b = noticeService.removeById(id);
        if (b){
            // 清理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg("删除公告/通知成功！");
        }else {
            dataView.setCode(100);
            dataView.setMsg("删除公告/通知失败！");
        }
        return dataView;
    }

    /**
     * 批量删除数据
     * @param ids
     * @return
     */
    @HoneyLogs(operation = "批量删除", type = LogType.BATCH_DELETE, menu = MenuType.SYSNOTICE)
    @PostMapping("/batchDelete")
    public DataView batchDelete(List<Integer> ids) {
        DataView dataView = new DataView();

        try {
            noticeService.removeByIds(ids);
            // 清理相关缓存
            clearRelatedCaches();
            dataView.setCode(200);
            dataView.setMsg("批量删除公告/通知成功");
        } catch (Exception e) {
            e.printStackTrace();
            dataView.setCode(500);
            dataView.setMsg("批量删除公告/通知失败：" + e.getMessage());
        }
        return dataView;

    }

    /**
     * 生成唯一缓存键
     */
    private String generateCacheKey(NoticeVo vo) {
        return String.format("%sselectAllNotice:page-%d_limit-%s_title-%s_type-%s_content-%s_status-%s_" +
                        "createdUser-%s_createTime-%s_modifiedUser-%s_modifiedTime-%s",
                CACHE_PREFIX,
                vo.getPage(),
                vo.getLimit(),
                org.springframework.util.StringUtils.hasText(vo.getTitle()) ? vo.getTitle() : "all",
                org.springframework.util.StringUtils.hasText(vo.getType()) ? vo.getType() : "all",
                org.springframework.util.StringUtils.hasText(vo.getContent()) ? vo.getContent() : "all",
                org.springframework.util.StringUtils.hasText(vo.getStatus()) ? vo.getStatus() : "all",
                org.springframework.util.StringUtils.hasText(vo.getCreatedUser()) ? vo.getCreatedUser() : "all",
                vo.getCreateTime() != null ? vo.getCreateTime() : 0,
                org.springframework.util.StringUtils.hasText(vo.getModifiedUser()) ? vo.getModifiedUser() : "all",
                vo.getModifiedTime() != null ? vo.getModifiedTime() : 0);
    }

    /**
     * 异步缓存结果
     */
    private void cacheResultAsync(String key, DataView data) {
        new Thread(() -> {
            try {
                redisUtil.set(key, data, CACHE_EXPIRE);
                logger.info("成功缓存数据 Key: {}", key);
            } catch (Exception e) {
                logger.error("异步缓存设置失败 Key: {}", key, e);
            }
        }).start();
    }

    /**
     * 清理相关缓存
     */
    private void clearRelatedCaches() {
        try {
            redisUtil.deletePattern(CACHE_PREFIX + "*");
            logger.info("成功清理日志相关缓存");
        } catch (Exception e) {
            logger.error("缓存清理失败", e);
        }
    }
}
